/**
 * 该模块提供旋转等待的 SpinWait 。
 * License: BSD
 * Authors: Lucifer (786325481@QQ.com)
 * Copyright: Copyright (C) 2008 Lucifer. All rights reserved.
 */
module system.threading.synchronization.SpinWait;

import system.Environment;
import system.threading.ThreadUtility;

/**
 * 提供旋转等待的并行数据结构。
 */
public struct SpinWait
{
	package const int yieldThreshold = 25;
	
	private int theCount;

	private static const bool isSingleProcessor;

	static this()
	{
		/*
		 * 判断是否单处理器系统。
		 */
		isSingleProcessor = Environment.processorCount == 1;
	}

	/**
	 * 执行旋转等待。
	 */
	public void spinOnce()
	{
		if( nextSpinWillYield() )
		{
			auto numeric = (theCount >= yieldThreshold ) ? (theCount - yieldThreshold) : theCount;
			if( numeric % 10 == 1 )
			{
				sleep(0);
			}
			else if( numeric % 10 == 9 )
			{
				sleep(1);
			}
			else
			{
				yield();
			}
		}
		else
		{
			spinWait(cast(int)(this.theCount * 1.28F) + 1);
		}
		theCount = (theCount == int.max) ? yieldThreshold : (theCount+1);
	}

	/**
	 * 判断下一次调用是否会迭代处理器，触发强制上下文切换。
	 * Comments: 在单处理器上，总会迭代。多处理器则可能会在某个旋转计数上迭代。
	 */
	public bool nextSpinWillYield()
	{
		if( !isSingleProcessor )
		{
			return this.theCount >= yieldThreshold;
		}

		return true;
	}

	/**
	 * 重置内部旋转计数。
	 * Comments: 这会使得旋转行为如初次调用。
	 *           如果 SpinWait 对象多次重用，你或许会重置以免偶然迭代过长。
	 */
	public void reset()
	{
		theCount = 0;
	}
	/**
	 * 获取 spinOnce 该实例被调用的次数。
	 */
	public int count()
	{
		return theCount;
	}

}